package com.zhuchang.self_rpc.test.server;

import com.zhuchang.self_rpc.test.codec.RpcRequest;
import com.zhuchang.self_rpc.test.codec.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.cglib.reflect.FastClass;
import org.springframework.cglib.reflect.FastMethod;

import java.lang.reflect.InvocationTargetException;
import java.util.Map;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * @Author RenPu
 * @Date 2021/8/18 14:59
 * @Version 1.0
 * @Description: 基于netty自定义RPC框架：服务端业务执行器的编写
 **/

@Slf4j
public class RpcServerHandler extends SimpleChannelInboundHandler<RpcRequest> {

    private Map<String, Object> handlerMap;

    //创建线程池，异步提交任务处理
    ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(16, 16, 600L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(65536));

    public RpcServerHandler(Map<String, Object> handlerMap) {
        this.handlerMap = handlerMap;
    }

    @Override
    protected void channelRead0(ChannelHandlerContext ctx, final RpcRequest rpcRequest) throws Exception {
        threadPoolExecutor.submit(new Runnable() {
            public void run() {

                //创建响应对象
                RpcResponse rpcResponse = new RpcResponse();

                //将请求的id，写回响应对象里，便于异步处理
                rpcResponse.setRequestId(rpcRequest.getRequestId());
                try {
                    //解析rpcRequest的方法handler
                    Object result = handler(rpcRequest);
                    rpcResponse.setResult(result);
                } catch (Throwable e) {
                    rpcResponse.setThrowable(e);
                    log.info("rpc service handle Throwable:" + e);
                }


                //2：从handlerMap里通过key获取对应的实现类的实例（bean）

                //4：将结果响应给调用方

            }
        });

    }


    /**
     * 1：解析rpcRequest对象的内容
     * 2：通过反射（jdk or cglib）获取对应的对象，调用具体的方法并传递传参
     *
     * @param rpcRequest
     * @return
     */
    private Object handler(RpcRequest rpcRequest) throws InvocationTargetException {
        String className = rpcRequest.getClassName();

        //根据接口的全限定名称，获取对应的实现类的实例以及类对象
        Object serviceRef = handlerMap.get(className);
        Class<?> serviceClass = serviceRef.getClass();

        //获取请求的，参数类型，具体参数，方法名称
        Object[] parameters = rpcRequest.getParameters();
        String methondName = rpcRequest.getMethondName();
        Class<?>[] parameterTypes = rpcRequest.getParameterTypes();

        //通cglib动态代理，获取对象并调用方法进行处理
        FastClass fastClass = FastClass.create(serviceClass);

        //获取方法对象
        FastMethod method = fastClass.getMethod(methondName, parameterTypes);

        //通过方法对象，传入对象实例+参数获取对应的结果
        return method.invoke(serviceRef, parameters);
    }


    /**
     * 异常处理，关闭资源
     */
    @Override
    public void exceptionCaught(ChannelHandlerContext cxt, Throwable cause) {
        log.info("server caught Throwable :" + cause);
        cxt.close();

    }
}
